// 定义引脚
const int shengyinPin = 33;            // 定义声音检测引脚对应的引脚号
const int doorLockStatusPin = 22;      // 定义车门锁状态引脚对应的引脚号
const int doorOpenCloseStatusPin = 23; // 定义车门开闭状态对应的引脚号
const int UnlockPin = 15;              // 定义车门解锁状态引脚对应的引脚号
const int LockPin = 2;                 // 定义车门锁闭状态引脚对应的引脚号
const int UnlockOUTPin = 5;            // 定义车门解锁输出引脚对应的引脚号
const int LockOUTPin = 17;             // 定义车门锁闭输出引脚对应的引脚号
const int LFOUTPin = 13;               // 定义扫描钥匙输出引脚对应的引脚号
const int ACC_pin = 12;                // 定义ACC引脚状态引脚对应的引脚号
const int ACCOUT_pin = 16;             // 定义ACC引脚输出引脚对应的引脚号
const int Status_pin = 14;             // 定义锁状态引脚对应的引脚号

// 将存储状态值设置为布尔类型，以下分别表示对应状态
int sj = 0;
bool dooorLock = false;                     // 开锁状态
bool doorLockStatus = false;                // 用于存储门锁状态标识
bool doorOpenCloseStatus = false;           // 用于存储车门开闭状态标识
bool jianCeYaoShi = false;                  // 请求执行钥匙状态
bool jianCeYaoShiStatus = false;            // 请求执行钥匙状态标识
bool yklock1 = false;                       // 遥控开锁状态
bool yklock2 = false;                       // 遥控开锁状态
bool startYklock = false;                   // 遥控开锁状态标识
bool startlockpin = false;                  // 锁车动作状态标识
bool startUnlockpin = false;                // 解锁动作状态标识
bool startACCpin = false;                   // ACC动作状态标识
int shengyinStatus = 0;                     // 声音信号强度
unsigned long LockLastMillis = 0;           // 时间戳，用于延时
unsigned long doorLocklastDebounceTime = 0; // 用于记录上次引脚状态改变的时间，用于防抖计时
unsigned long doorOpenlastDebounceTime = 0; // 用于记录上次引脚状态改变的时间，用于防抖计时
unsigned long ACClastDebounceTime = 0;      // 用于记录上次引脚状态改变的时间，用于防抖计时
const unsigned long debounceDelay = 500;    // 防抖延迟时间，单位毫秒，可根据实际情况调整

// 遥控解锁
void IRAM_ATTR UnlockcheckSwitch()
{
    startUnlockpin = digitalRead(UnlockPin);
    sj = 0;
    if (yklock1)
    {
        if (startUnlockpin)
        {
            yklock2 = true;
        }
        // digitalWrite(UnlockOUTPin, digitalRead(UnlockPin));
    }
    else
    {
        LockLastMillis = millis();
        if (startUnlockpin && !startACCpin)
        {
            yklock1 = true;
        }
    }
}

// 遥控锁车
void IRAM_ATTR LockcheckSwitch()
{
    sj++;
    if (!yklock1)
    {
        digitalWrite(LockOUTPin, digitalRead(LockPin));
    }
    else
    {
        startlockpin = digitalRead(LockPin);
        LockLastMillis = millis();
        if (startlockpin && !startACCpin)
        {
            yklock1 = false;
            digitalWrite(ACCOUT_pin, LOW); // 锁车后关闭ACC电源
            if (doorOpenCloseStatus)
            {
                dooorLock = false;
            }
        }
    }
}

// 执行解锁函数
void Unlock()
{
    sendtoTCPServer("执行解锁");
    digitalWrite(UnlockOUTPin, HIGH);
    delay(500);
    digitalWrite(UnlockOUTPin, LOW);
}

// 执行锁车函数
void Lock()
{
    sendtoTCPServer("执行锁车");
    digitalWrite(LockOUTPin, HIGH);
    delay(500);
    digitalWrite(LockOUTPin, LOW);
}

// 实时检测遥控器模块函数
void Yaokqi()
{
    if (yklock1 != startYklock)
    {
        startYklock = yklock1;
        sendtoTCPServer(yklock1 ? "有钥匙" : "无钥匙");
    }

    if (digitalRead(doorOpenCloseStatusPin) != doorOpenCloseStatus)
    { // 开关门
        if (doorOpenlastDebounceTime == 0)
        {
            doorOpenlastDebounceTime = millis();
        }
        else if (millis() - doorOpenlastDebounceTime > debounceDelay)
        {
            doorOpenCloseStatus = digitalRead(doorOpenCloseStatusPin);
            LockLastMillis = millis();
            doorOpenlastDebounceTime = 0;
            if (doorOpenCloseStatus)
            {
                sendtoTCPServer("关门");
                dooorLock = true;
            }
            else
            {
                sendtoTCPServer("开门");
            }
        }
    }
    else
    {
        doorOpenlastDebounceTime = 0;
    }

    if (digitalRead(doorLockStatusPin) != doorLockStatus)
    { // 门锁
        if (doorLocklastDebounceTime == 0)
        {
            doorLocklastDebounceTime = millis();
        }
        else if (millis() - doorLocklastDebounceTime > debounceDelay / 100)
        {
            doorLockStatus = digitalRead(doorLockStatusPin);
            LockLastMillis = millis();
            doorLocklastDebounceTime = 0;
            if (!doorLockStatus)
            {
                sendtoTCPServer("已解锁");
                jianCeYaoShi = false;
            }
            else
            {
                sendtoTCPServer("已锁车");
            }
        }
    }
    else
    {
        doorLocklastDebounceTime = 0;
    }

    if (digitalRead(ACC_pin) != startACCpin)
    { // ACC电源
        if (ACClastDebounceTime == 0)
        {
            ACClastDebounceTime = millis();
        }
        else if (millis() - ACClastDebounceTime > debounceDelay)
        {
            startACCpin = digitalRead(ACC_pin);
            ACClastDebounceTime = 0;
            if (!startACCpin)
            {
                sendtoTCPServer("熄火");
            }
            else if (startACCpin)
            {
                digitalWrite(ACCOUT_pin, HIGH);
                sendtoTCPServer("启动");
            }
        }
    }
    else
    {
        ACClastDebounceTime = 0;
    }

    shengyinStatus = analogRead(shengyinPin);
    if (shengyinStatus >= 1000)
    {
        if (!jianCeYaoShi)
        {
            jianCeYaoShi = true;
            sendtoTCPServer("检测开");
        }
        LockLastMillis = millis();
    }
    else if (!yklock1 && jianCeYaoShi && millis() - LockLastMillis > 10000)
    {
        jianCeYaoShi = false;
        sendtoTCPServer("检测关");
    }

    if (jianCeYaoShi && yklock1 && !startACCpin && !digitalRead(ACCOUT_pin))
    { // 扫描钥匙
        if (digitalRead(doorLockStatusPin))
        {
            // delay(500);
            Unlock();
        }
    }

    if (!yklock1 && !doorLockStatus)
    { // 无钥匙自动锁车
        if (millis() - LockLastMillis > 3000)
        {
            if (doorOpenCloseStatus)
            {
                Lock();
            }
            else
            {
                sendtoTCPServer("车门未关");
            }
            LockLastMillis = millis();
        }
    }

    if (yklock2)
    {
        Lock();

        Unlock();
        yklock2 = false;
    }

    if (sj >= 10)
    {
        if (client_bemfa_WiFiClient.connected())
        {
            sendtoTCPServer("升级");
            updateBin();
        }
    }
}

// 定义记录每个时间段敲击次数的数组，假设最多记录10个时间段的敲击次数，可按需调整大小
String knockCountArray = "";
// 数组索引，用于记录当前存储位置，初始化为0，表示从数组的第一个元素开始存储敲击次数数据
int arrayIndex = 0;
// 时间间隔，设定为2秒钟，单位是毫秒，用于划分统计敲击次数的时间段
const int timeInterval = 500;
// 用于记录每个时间段的起始时间，初始化为0，后续会根据系统时间来更新，以判断是否达到时间间隔
unsigned long intervalStartTime = 0;
// 用于记录当前时间段内的敲击次数，每检测到一次有效的敲击就加1，每个时间段结束后重置为0
int currentKnockCount = 0;
// 标识位，用于标记是否处于一次有效的敲击过程中，初始化为假（即当前未处于敲击过程中）
bool knockInProgress = false;
// 预设密码相关
// 用于存储设置的密码敲击次数序列，假设密码最长为10次敲击，可按需调整大小
int setPassword[5]{2, 3, 5, 3, 2};
// 用于存储输入的密码敲击次数序列
int inputPassword[5];
// 记录设置密码时的当前位置索引，初始化为0，随着敲击次数存储逐步递增
int setPasswordIndex = 0;
// 记录输入密码时的当前位置索引，初始化为0，在比对过程中根据情况变化
int inputPasswordIndex = 0;
// 标记是否处于设置密码模式，初始为假，即默认处于输入密码模式
bool isSettingPassword = false;
// 标记输入的密码是否验证成功，初始为假
bool passwordVerified = false;
// 记录已经正确比对的密码位数，初始为0，用于区分部分密码正确和整个密码输入完整且正确的情况
int correctPasswordCount = 0;
// 用于记录第一次敲击三次的状态，初始化为false
bool firstThreeKnocksRecorded = false;
// 用于记录第二次敲击三次的状态，初始化为false
bool secondThreeKnocksRecorded = false;
// 用于记录第一次敲击三次后的时间戳，初始化为0
unsigned long firstThreeKnocksTime = 0;
// 设定两次敲击三次的时间间隔限制，比如3秒内完成两次敲击三次，单位毫秒，可按需调整
const int timeLimitBetweenKnocks = 4000;

// 敲击密码函数
void KnockCount()
{
    if (doorLockStatus && doorOpenCloseStatus && !yklock1)
    {
        shengyinStatus = analogRead(shengyinPin);
        unsigned long currentTime = millis(); // 获取当前系统的时间戳（以毫秒为单位），用于和时间段起始时间对比，判断是否达到设定的时间间隔
        // 判断敲击开始的条件：传感器值大于等于3000（意味着可能发生了敲击）且当前不在敲击过程中（knockInProgress为false）
        if (shengyinStatus >= 2000 && !knockInProgress)
        {
            // 数值高于3000且当前不在敲击过程中，视为敲击开始，设置标识位为真，表示进入敲击过程
            knockInProgress = true;
            // 将当前时间段内的敲击次数加1，开始统计本次敲击过程中的敲击次数
            currentKnockCount++;
        }
        // 判断敲击结束的条件：传感器值小于1000（说明敲击动作可能结束了）且当前处于敲击过程中（knockInProgress为true）
        else if (shengyinStatus < 2000 && knockInProgress)
        {
            // 数值低于1000且当前处于敲击过程中，视为敲击结束，设置标识位为假，意味着本次敲击过程结束
            knockInProgress = false;
            intervalStartTime = currentTime; // 更新intervalStartTime为当前时间，也就是将下一个时间段的起始时间设置为当前时间，重新开始新的时间间隔统计
        }

        if (currentKnockCount >= 2 && currentTime - intervalStartTime >= timeInterval)
        { // 判断当前时间与本时间段起始时间的差值是否大于等于设定的时间间隔（1000毫秒），如果是则表示一个统计时间段结束了

            if (!secondThreeKnocksRecorded)
            {
                sendtoTCPServer("识别码:" + String(currentKnockCount));
                if (currentKnockCount == 3)
                { // 判断是否敲击了三次 进入密码验证
                    if (!firstThreeKnocksRecorded)
                    {
                        firstThreeKnocksRecorded = true;

                        firstThreeKnocksTime = currentTime;
                    }
                    else if (firstThreeKnocksRecorded && !secondThreeKnocksRecorded)
                    {
                        if (currentTime - firstThreeKnocksTime <= timeLimitBetweenKnocks)
                        {
                            secondThreeKnocksRecorded = true;
                            // 这里表示两次敲击三次的有效操作已完成，进入输入密码模式
                            inputPasswordIndex = 0;
                            correctPasswordCount = 0;
                            passwordVerified = false;
                            isSettingPassword = false;
                            Lock();
                            sendtoTCPServer("输入密码"); // 重置相关输入密码状态相关变量，准备开始新的密码输入尝试
                            if (Lanya())
                            {
                                Unlock();
                                sendtoTCPServer("手机解锁");
                            }
                        }
                        else
                        {
                            firstThreeKnocksRecorded = false;
                            secondThreeKnocksRecorded = false;
                            // sendtoTCPServer( "两次输入时间过长");
                        }
                    }
                }
                else if (currentKnockCount == 5)
                { // 判断是否敲击了五次 进入设置密码
                    if (!firstThreeKnocksRecorded)
                    {
                        firstThreeKnocksRecorded = true;

                        firstThreeKnocksTime = currentTime;
                    }
                    else if (firstThreeKnocksRecorded && !secondThreeKnocksRecorded)
                    {
                        if (currentTime - firstThreeKnocksTime <= timeLimitBetweenKnocks)
                        {
                            secondThreeKnocksRecorded = true;
                            // 这里表示两次敲击三次的有效操作已完成，进入输入密码模式
                            setPasswordIndex = 0;
                            inputPasswordIndex = 0;
                            correctPasswordCount = 0;
                            passwordVerified = false;
                            isSettingPassword = true;
                            Lock();
                            sendtoTCPServer("设置密码"); // 重置相关输入密码状态相关变量，准备开始新的密码输入尝试
                        }
                        else
                        {
                            firstThreeKnocksRecorded = false;
                            secondThreeKnocksRecorded = false;
                            // sendtoTCPServer( "两次输入时间过长");
                        }
                    }
                }
                else if (firstThreeKnocksRecorded)
                {
                    firstThreeKnocksRecorded = false;
                    secondThreeKnocksRecorded = false;
                    // sendtoTCPServer( "两次识别码不一样");
                }
                // else
                // {
                //     sendtoTCPServer( "识别码错误");
                // }
            }
            else if (secondThreeKnocksRecorded)
            {
                knockCountArray += String(currentKnockCount); // 将当前时间段内统计好的敲击次数存储到knockCountArray数组中，存储位置由arrayIndex决定
                sendtoTCPServer("密码:" + knockCountArray);
                if (isSettingPassword)
                { // 判断是否处于设置密码模式
                    // 在设置密码模式下，将敲击次数存入设置密码数组，存储位置由setPasswordIndex决定
                    setPassword[setPasswordIndex] = currentKnockCount;
                    setPasswordIndex++; // 将设置密码的索引加1，指向下一个存储位置
                    if (setPasswordIndex == 5)
                    {
                        Lock();
                        sendtoTCPServer("密码设置成功");
                        isSettingPassword = false;
                        setPasswordIndex = 0;
                        knockCountArray = "";
                        sendtoTCPServer("输入密码");
                    }
                }
                else
                { // 如果处于输入密码模式
                    // 在输入密码模式下，将敲击次数存入输入密码数组，存储位置由inputPasswordIndex决定
                    inputPassword[inputPasswordIndex] = currentKnockCount;
                    inputPasswordIndex++; // 将输入密码的索引加1，指向下一个存储位置

                    // 实时密码比对逻辑，只要输入了至少一位密码就开始比对
                    if (inputPasswordIndex > 0)
                    {
                        // 判断当前刚存入输入密码数组的这一位（索引为inputPasswordIndex - 1，因为数组索引从0开始）与预设密码对应位置的数值是否相等
                        if (inputPassword[inputPasswordIndex - 1] == setPassword[inputPasswordIndex - 1])
                        {
                            correctPasswordCount++; // 如果相等，说明这一位密码比对正确，将正确比对的密码位数加1
                            // 判断已经正确比对的密码位数是否大于等于预设密码的长度，即判断是否完整比对完整个密码
                            if (correctPasswordCount >= sizeof(setPassword) / sizeof(setPassword[0]))
                            {
                                // 如果已经比对完整个密码序列，说明密码验证成功
                                passwordVerified = true;
                                knockCountArray = "";
                                inputPasswordIndex = 0;
                                correctPasswordCount = 0;
                                firstThreeKnocksRecorded = false;
                                secondThreeKnocksRecorded = false;
                                Serial.println("Password verified successfully!");
                                sendtoTCPServer("密码正确");
                                Unlock();
                                // 在这里可以添加验证成功后的操作，比如解锁设备、执行特定功能等
                            }
                        }
                        else
                        {
                            // 如果当前输入的这一位密码与预设密码对应位不一致，说明输入错误
                            // 重置输入密码相关索引和正确比对的密码位数，等待下一次完整输入尝试
                            sendtoTCPServer("密码错误");
                            knockCountArray = "";
                            inputPasswordIndex = 0;
                            correctPasswordCount = 0;
                            firstThreeKnocksTime = currentTime; // 当密码输入错误重新记时 避免输入超时
                        }
                    }
                }
            }

            currentKnockCount = 0;           // 重置当前时间段内的敲击次数为0，为下一个时间段的统计做准备
            intervalStartTime = currentTime; // 更新intervalStartTime为当前时间，也就是将下一个时间段的起始时间设置为当前时间，重新开始新的时间间隔统计
        }
        if (firstThreeKnocksRecorded && !secondThreeKnocksRecorded && currentTime - firstThreeKnocksTime > 3000)
        {
            firstThreeKnocksRecorded = false;
            secondThreeKnocksRecorded = false;
            sendtoTCPServer("输入超时");
        }
        else if (firstThreeKnocksRecorded && secondThreeKnocksRecorded && currentTime - firstThreeKnocksTime > 20000)
        {
            inputPasswordIndex = 0;
            correctPasswordCount = 0;
            firstThreeKnocksRecorded = false;
            secondThreeKnocksRecorded = false;
            sendtoTCPServer("输入超时");
        }
    }
}

void setup_wlrg()
{
    // 设置各引脚的模式
    pinMode(ACC_pin, INPUT);                // 将ACC状态引脚设置为输入模式
    pinMode(shengyinPin, INPUT);            // 将门锁状态引脚设置为输入模式
    pinMode(doorLockStatusPin, INPUT);      // 将门锁状态引脚设置为输入模式
    pinMode(doorOpenCloseStatusPin, INPUT); // 将车门开闭状态引脚设置为输入模式
    pinMode(UnlockPin, INPUT);              // 将车门解锁引脚设置为输入模式
    pinMode(LockPin, INPUT);                // 将车门锁闭引脚设置为输入模式
    pinMode(Status_pin, INPUT_PULLUP);      // 将车指示灯引脚设置为输入模式

    pinMode(UnlockOUTPin, OUTPUT); // 将车门解锁引脚设置为输出模式
    pinMode(LockOUTPin, OUTPUT);   // 将车门锁闭引脚设置为输出模式
    pinMode(ACCOUT_pin, OUTPUT);   // 将车门锁闭引脚设置为输出模式
    pinMode(LFOUTPin, OUTPUT);     // 将低频天线引脚设置为输出模式
    digitalWrite(LFOUTPin, HIGH);

    // 配置启动按键引脚的中断，下降沿触发（按下按键时电平从高变低触发），调用handleStartButtonInterrupt函数
    attachInterrupt(digitalPinToInterrupt(UnlockPin), UnlockcheckSwitch, CHANGE);
    attachInterrupt(digitalPinToInterrupt(LockPin), LockcheckSwitch, CHANGE);

    startACCpin = digitalRead(ACC_pin);
    doorLockStatus = digitalRead(doorLockStatusPin);
    doorOpenCloseStatus = digitalRead(doorOpenCloseStatusPin);
    LockLastMillis = millis();
    while (millis() - LockLastMillis < 3000)
    {
        if (!digitalRead(Status_pin))
        {
            yklock1 = true;
        }
        vTaskDelay(pdMS_TO_TICKS(10)); // 适当延时，避免线程空转占用过多资源，每次循环等待100毫秒（转换为系统节拍数）
    }
}

// 循环
void loop_wlrg()
{ // 无限循环，保证线程持续运行，不断检查是否需要执行启动逻辑
    Yaokqi();
    KnockCount();
}
